/*
 * entry.S - Entry point to system mode from user mode
 */

#include <asm.h>
#include <segment.h>
#include <error.h>
/** Max number of sys_call defined, for this deliver (4)**/
#define syscall_max_entries $35


/**************************************************/
/**** Save & Restore ******************************/
/**                                              **/
/** When we change to privilege level 0 (kernel) **/
/** (through an interrupt, a system call, an     **/
/** exception ...) we must save the state of the **/
/** currently running task (save).               **/
/**                                              **/
/** Stack layout in 'systemCall':                **/
/**                                              **/
/**   0(%esp) - %ebx    \                        **/
/**   4(%esp) - %ecx     |                       **/
/**   8(%esp) - %edx     |                       **/
/**   C(%esp) - %esi     | Register saved        **/
/**  10(%esp) - %edi     |  by 'save'            **/
/**  14(%esp) - %ebp     |                       **/
/**  18(%esp) - %eax     |                       **/
/**  1C(%esp) - %ds      |                       **/
/**  20(%esp) - %es      |                       **/
/**  24(%esp) - %fs      |                       **/
/**  28(%esp) - %gs     /                        **/
/**  2C(%esp) - %eip    \                        **/
/**  30(%esp) - %cs      |                       **/
/**  34(%esp) - %eflags  |  Return context saved **/
/**  38(%esp) - %oldesp  |   by the processor.   **/
/**  3C(%esp) - %oldss  /                        **/
/**                                              **/
/**************************************************/

#define SAVE_ALL \
      pushl %gs; \
      pushl %fs; \
      pushl %es; \
      pushl %ds; \
      pushl %eax; \
      pushl %ebp; \
      pushl %edi; \
      pushl %esi; \
      pushl %edx; \
      pushl %ecx; \
      pushl %ebx; \
      movl $__KERNEL_DS, %edx;    \
      movl %edx, %ds;           \
      movl %edx, %es 

#define RESTORE_ALL \
	popl %ebx;\
	popl %ecx;\
	popl %edx;\
	popl %esi;\
	popl %edi;\
	popl %ebp;\
	popl %eax;\
	popl %ds;\
	popl %es;\
	popl %fs;\
	popl %gs
	
/** END OF INTERRUPTION **/
#define EOI \
	movb $0x20, %al;\
	outb %al, $0x20

/** Interrupt Handlers declaration (REVISE IT, NOT FINISHED**/ 
// Adresses 1 - 17 (check wicht interruptions must erase the stack interruption 4byte saved by the interrution)

ENTRY(divide_error_handler);
	SAVE_ALL;
	call divide_error_routine;
	RESTORE_ALL;
	iret;

ENTRY(debug_handler);
	SAVE_ALL;
	call debug_routine;
	RESTORE_ALL;
	iret;

ENTRY(nm1_handler);
	SAVE_ALL;
	call nm1_routine;
	RESTORE_ALL;
	iret;	

ENTRY(breakpoint_handler);
	SAVE_ALL;
	call breakpoint_routine;
	RESTORE_ALL;
	iret;


ENTRY(overflow_handler);
	SAVE_ALL;
	call overflow_routine;
	RESTORE_ALL;
	iret;

ENTRY(bounds_check_handler);
	SAVE_ALL;
	call bounds_check_routine;
	RESTORE_ALL;
	iret;

ENTRY(invalid_opcode_handler);
	SAVE_ALL;
	call invalid_opcode_routine;
	RESTORE_ALL;
	iret;

ENTRY(device_not_available_handler);
	SAVE_ALL;
	call device_not_available_routine;
	RESTORE_ALL;
	iret;

ENTRY(double_fault_handler);
	SAVE_ALL;
	call double_fault_routine;
	addl $4,%esp;  
	RESTORE_ALL;
	iret;


ENTRY(coprocessor_segment_overrun_handler);
	SAVE_ALL;
	call coprocessor_segment_overrun_routine;
	RESTORE_ALL;
	iret;

ENTRY(invalid_tss_handler);
	SAVE_ALL;
	call invalid_tss_routine;
	addl $4,%esp;  
	RESTORE_ALL;
	iret;

ENTRY(segment_not_present_handler);
	SAVE_ALL;
	call segment_not_present_routine;
	addl $4,%esp;  
	RESTORE_ALL;
	iret;

ENTRY(stack_exception_handler);
	SAVE_ALL;
	call stack_exception_routine;
	addl $4,%esp;  
	RESTORE_ALL;
	iret;

ENTRY(general_protection_handler);
	SAVE_ALL;
	call general_protection_routine;
	addl $4,%esp;  
	RESTORE_ALL;
	iret;

ENTRY(page_fault_handler);
	SAVE_ALL;
	call page_fault_routine;
	addl $4,%esp;  
	RESTORE_ALL;
	iret;

ENTRY(floatin_point_error_handler);
	SAVE_ALL;
	call floatin_point_error_routine;
	RESTORE_ALL;
	iret;

ENTRY(alignment_check_handler);
	SAVE_ALL;
	call alignment_check_routine;
	addl $4,%esp;  
	RESTORE_ALL;
	iret;

// Hardware Exeption handlers adresses 32-42 (masked interrupts)

ENTRY(clock_handler);
	SAVE_ALL;
	call clock_routine;
	EOI
	RESTORE_ALL;
	iret;

ENTRY(keyboard_handler);
	SAVE_ALL;
	call keyboard_routine;
	EOI
	RESTORE_ALL;
	iret;
// Emili starts - Declaration of syscall handler

/*************** System call handler********************/

#system_call();
	ENTRY(system_call); 		//as other handlers
	SAVE_ALL;
	cmp syscall_max_entries,%eax; 	//compare %epx with our syscall_number
	jg not_valid; 			//conditional jump if the syscall number is greater than maximum

	cmpl $0,%eax; //if less that zero, then not valid as well
	jl not_valid;

is_valid: 				//else
	call *sys_call_table(,%eax,0x04);	//redirects to the corresponding entry of the table.
	jmp end_syscall;			//jumt to the end of sys call

	not_valid:			//only executed if %eax is out of range 
	movl $-ENOSYS, %eax 		//(less than 0 or more than syscall_max_entries)

end_syscall:
	movl %eax, 24(%esp);
	RESTORE_ALL;
	iret;
/*********************************************************/
/**                sys_call_table                       **/
/*********************************************************/
/**Each line is increasing the table.		       	**/
/**All non implemented syscalls number before one that	**/
/**is implemented must be declared as sys_ni_call. 	**/
/**For this deliveri 4 (write_syscall is the last)	**/
/*********************************************************/
#sys_call table
	ENTRY(sys_call_table) 
		.long sys_ni_call 	//0//
		.long sys_exit 		//1 sys_exit
		.long sys_fork 		//2 sys_fork
		.long sys_ni_call
		.long sys_write   	//4// write sys call address
		.long sys_ni_call
		.long sys_ni_call
		.long sys_ni_call
		.long sys_ni_call
		.long sys_ni_call
		.long sys_ni_call
		.long sys_ni_call
		.long sys_ni_call
		.long sys_ni_call
		.long sys_ni_call
		.long sys_ni_call
		.long sys_ni_call
		.long sys_ni_call
		.long sys_ni_call
		.long sys_ni_call
		.long sys_getpid 	//20 sys_getpid
		.long sys_sem_init 	//21 sys_sem_init
		.long sys_sem_wait 	//22 sys_sem_wait
		.long sys_sem_signal 	//23 sys_sem_signal
		.long sys_sem_destroy 	//24 sys_sem_destroy
		.long sys_ni_call 	//25
		.long sys_ni_call
		.long sys_ni_call
		.long sys_ni_call
		.long sys_ni_call
		.long sys_ni_call 	//30
		.long sys_ni_call
		.long sys_ni_call
		.long sys_ni_call
		.long sys_nice 		//34 sys_nice
		.long sys_get_stats 	//35 sys_get_stats	

